﻿using Furion;
using Furion.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Reflection;
using System.Threading.Tasks;
using UpperComputer.Application;
using YFurion.Application;
using YFurion.Attributes;
using YFurion.Controllers.Extensions;
using YFurion.Extensions;
using YFurion.Session;
using YFurion.Session.Extensions;

namespace UpperComputer.Web.Core
{
    public class JwtHandler : AppAuthorizeHandler
    {
        public override async Task<bool> PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
        {
            IYSession ySession = App.GetService<IYSession>();
            if (ySession.Account.Equals("Admin"))
            {
                return true;
            }

            AuthorizationFilterContext authorizationFilterContext = context.Resource.As<AuthorizationFilterContext>();
            ControllerActionDescriptor controllerActionDescriptor = authorizationFilterContext.ActionDescriptor.AsControllerActionDescriptor();
            if (controllerActionDescriptor.MethodInfo.IsDefined(typeof(OnlyCheckLoginAttribute))
                || controllerActionDescriptor.MethodInfo.DeclaringType.IsDefined(typeof(OnlyCheckLoginAttribute)))
            {
                return true;
            }

            IBaseUserService baseUserService = App.GetService<IBaseUserService>();
            string[] roleCodes = await baseUserService.GetRoleCodesCache(new BaseUserDto { Id = ySession.SubjectId, Account = ySession.Account });
            string[] permissionCodes = ySession.GetPermissionCodes(controllerActionDescriptor, authorizationFilterContext.HttpContext);
            IBaseRolePermissionService rolePermissionService = App.GetService<IBaseRolePermissionService>();
            PagedResultDto<BaseRolePermissionDto> pagedResultDto = await rolePermissionService.GetAll(new BaseRolePermissionResultRequestDto
            {
                MaxResultCount = 1,
                PermissionCodes = permissionCodes,
                RoleCodes = roleCodes
            });
            if (pagedResultDto.TotalCount == 0)
            {
                return false;
            }

            return true;
        }

        public override async Task HandleAsync(AuthorizationHandlerContext context)
        {
            IYSession ySession = App.GetService<IYSession>();
            if (ySession.AutoRefreshToken(context.GetCurrentHttpContext()))
            {
                bool isLogin = await IsLoginAsync(ySession);
                if (isLogin)
                {
                    await AuthorizeHandleAsync(context);
                }
                else
                {
                    context.Fail();
                }
            }
            else
            {
                context.Fail();
            }
        }

        private async Task<bool> IsLoginAsync(IYSession ySession)
        {
            IBaseUserService baseUserService = App.GetService<IBaseUserService>();
            BaseUserResultDto baseUserResultDto = await baseUserService.GetCacheById(ySession.SubjectId);
            if (baseUserResultDto == null)
            {
                return false;
            }

            string account = baseUserResultDto.Account, userName = baseUserResultDto.DisplayName;
            if (account.IsNullOrWhiteSpace()
                || userName.IsNullOrWhiteSpace()
                || !baseUserResultDto.IsActive)
            {
                return false;
            }

            ySession.Account = account;
            ySession.UserName = userName;

            return true;
        }
    }
}